using System;
using System.Collections;
using System.IO;

namespace Thinktecture.Tools.Web.Services.CodeGeneration.Driver
{
	/// <summary>
	/// Summary description for ResultFileWriter.
	/// </summary>
	public class ResultFileWriter
	{
		bool writeToConsole = false;
        bool overwrite = false;

		public ResultFileWriter(bool consoleOutput, bool overwrite)
		{
			writeToConsole = consoleOutput;
            this.overwrite = overwrite;
		}

		// CSC 02/02 Changed parameter type from ArrayList to SourceFiles
		public void WriteProxy( SourceFiles results, ContractFirstArguments args )
		{
			if( false == args.GenerateServerCode )
			{
				WriteClientCode(results, args);
			}
		}

		// CSC 02/02 Changed parameter type from ArrayList to SourceFiles
		public void WriteSerivce(SourceFiles results, ContractFirstArguments args)
		{
			// CSC 11/24/2004
			// Allowed independent generation of proxy and service code
			if( true == args.GenerateServerCode )
			{
				WriteServerCode(results,args);
			}
		}

        // BDS 09/29/2006. Added this procedure to write the data contract files to the disk.
        public void WriteDataContract(SourceFiles results)
        {
            for (int i = 0; i < results.Count; i++)
            {
                WriteFile(results[i].FileName, results[i].SourceCode);
            }            
        }

		// CSC 02/02 Changed parameter type from ArrayList to SourceFiles
		private void WriteClientCode( SourceFiles results, ContractFirstArguments args )
		{
			// CSC 02/13, reinstated filename code and added
			// check for missing file name from engine

			// build the output file name, if it's not set 
			// by the code generation engine
			string extension = Path.GetExtension(args.ProxyFileName);
			string proxyPath = args.ProxyFileName;
			if (null == extension
				|| 0 == extension.Length
				|| "." + args.CodeLanguage.ToLower() != extension.ToLower())
			{
				proxyPath += ".";
				proxyPath += args.CodeLanguage.ToLower();
			}
			 
            // BDS 12/23/2005: Proxy file name is never set to an empty string 
            // by the code generation engine. It atleast contains the file extension.
			if (null == results.ProxyFile.FileName
				|| (null != results.ProxyFile.FileName
					&& 3 >= results.ProxyFile.FileName.Length))
			{
				results.ProxyFile.FileName = proxyPath;
			}

			// CSC 02/02/05 new SourceFile class
			// BDS 12/23/2005: Write all the files in the 'results' collection.
            for (int i = 0; i < results.Count; i++)
            {
                WriteFile(results[i].FileName, results[i].SourceCode);
            }            
		}

        /// <summary>
        ///  This method treats everything after the 
        ///  FIRST dot as the extension, not everything
        ///  after the last dot.
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        private string GetFileNameWithoutExtensionReally(string path)
		{
			string name = Path.GetFileNameWithoutExtension( path );
			int dotLocation = name.IndexOf(".");
			if( dotLocation != -1 )
			{
				name = name.Substring( 0, dotLocation );
			}
			return name;
		}

		private void WriteFile( string fileName, string content )
		{
			int uniqueCount = 1;
			string uniqueFileName = fileName;

            if (!overwrite)
            {
                string fileNameWithoutExtension = GetFileNameWithoutExtensionReally(fileName);
                while (true == File.Exists(uniqueFileName))
                {
                    uniqueFileName = fileName.Replace(fileNameWithoutExtension, fileNameWithoutExtension + uniqueCount.ToString());
                    uniqueCount++;
                }
            }

			using (FileStream file = new FileStream(uniqueFileName, FileMode.Create))
			{
				if( true == writeToConsole )
				{
					Console.WriteLine( String.Format("Writing File: {0}", uniqueFileName));
				}
				StreamWriter writer = new StreamWriter(file, System.Text.Encoding.UTF8);
				writer.Write(content);
				writer.Close();
			}
		}

		internal static string AppendExtension(string originalName, string languageSuffix)
		{
			string newName = originalName;
			if( true == Path.HasExtension(originalName) )
			{
				// do we alredy have the right extension?
				if( false == originalName.ToLower().EndsWith(languageSuffix.ToLower()) )
				{
					newName = Path.GetFileNameWithoutExtension(originalName) + "." + languageSuffix;
				}
			}
			else
			{
				// no extension to begin with
				// add it
				newName = originalName + "." + languageSuffix;
			}
			return newName;
		}

		// CSC 02/02 Changed parameter type from ArrayList to SourceFiles
		private void WriteServerCode( SourceFiles results, ContractFirstArguments args )
		{
			System.Diagnostics.Debug.Assert( null != results, "output file collection is null" );
			// CSC 02/13, reinstated filename code and build file names from 
			// command-line parameters if necessary

			// CSC 11/19/2004
			// added new parameters for file names
			string serviceStubName = AppendExtension(args.ServiceStubFileName, args.CodeLanguage);
			// CSC 11/22/2004
			// Made sure output file goes to the right directory .. and assumed that 
			// CheckFileNames was called
			string asmxFileName;
			string extensionToRemove = ".asmx." + args.CodeLanguage.ToLower();

			if (true == args.WebServiceImplementationFile.EndsWith(extensionToRemove))
			{
				asmxFileName = AppendExtension(args.WebServiceImplementationFile.Replace(extensionToRemove, ""), "asmx");
			}
			else
			{
				asmxFileName = AppendExtension(args.WebServiceImplementationFile, "asmx");
			}
			string implementationName = AppendExtension(args.WebServiceImplementationFile, "asmx." + args.CodeLanguage);

			if (null != results.AsmxFile )
			{
				if( null == results.AsmxFile.FileName 
					   || (null != results.AsmxFile.FileName 
					   && 0 == results.AsmxFile.FileName.Length))
				{
					results.AsmxFile.FileName = asmxFileName;
				}
			}

			if (null != results.ServiceImplementation )
			{
				if( null == results.ServiceImplementation.FileName 
					|| (null != results.ServiceImplementation.FileName 
					&& 3 >= results.ServiceImplementation.FileName.Length))
				{
					results.ServiceImplementation.FileName = implementationName;
				}
			}
			// CSC 02/02 wrote against the new SourceFile class
			for( int i = 0; i < results.Count; i++ )
			{				
				WriteFile( results[i].FileName, results[i].SourceCode );
			}
		}

		internal static string GetFileName( string source, string extension )
		{
			string retVal;
			try
			{
				// derive the filename for the generated filename from 
				// the source Url if it is one
				Uri url = new Uri(source);
				if( true == url.IsFile)
				{
					retVal = AppendExtension( url.LocalPath, extension );
				}
				else
				{
					retVal = AppendExtension(url.Segments[url.Segments.Length-1], extension);
				}
			}
			catch( UriFormatException )
			{
				// nothing that url-able ...
				// let's try a file
				retVal = AppendExtension(Path.GetFileName(source), extension);
			}
			System.Diagnostics.Debug.WriteLine(string.Format("Derived file name is: {0}", retVal));
			return retVal;
		}
	}
}
